package xyz.thoughtset.viewer.modules.api.service;

import cn.hutool.core.map.BiMap;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import xyz.thoughtset.viewer.modules.api.controller.RequestController;
import xyz.thoughtset.viewer.modules.api.dao.ApiInfoDao;
import xyz.thoughtset.viewer.modules.api.entity.ApiInfo;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@RequiredArgsConstructor(onConstructor =@__(@Autowired))
public class DynamicApiService implements InitializingBean {
    private volatile static BiMap<String, String> WORKINGBIMAP = new BiMap<>(new HashMap<>());
    private volatile static ConcurrentHashMap<String, RequestMappingInfo> REQINFOCACHE = new ConcurrentHashMap<>();
    private final ApplicationContext applicationContext;
    //将applicationContext转换为ConfigurableApplicationContext
//    private ConfigurableApplicationContext configurableApplicationContext;

    // 获取bean工厂并转换为DefaultListableBeanFactory
    private final DefaultListableBeanFactory defaultListableBeanFactory;
    private final RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Override
    public void afterPropertiesSet() throws Exception {

    }

    private String registerBean(ApiInfo apiInfo){
        String intfKey = apiInfo.getId();
        String beanName = "Bean_"+intfKey;
        putMappingWorking(beanName, apiInfo.getUrl());
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(RequestController.class);
        BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
        beanDefinition.getPropertyValues()
                .add("beanName",beanName)
                .add("apiInfo", apiInfo);
        //设置当前bean定义对象是单利的
        beanDefinition.setScope("singleton");
        defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinition);
        return beanName;
    }
    public void registerMapping(ApiInfo apiInfo) throws Exception {
        String path = apiInfo.getUrl();
        if (!StringUtils.hasText(path)) return;
        //先注册bean
        String beanName = registerBean(apiInfo);
//        RequetMappingHandlerMapping requestMappingHandlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
        if (!path.startsWith("/")) path = "/"+path;
        RequestMappingInfo requestMappingInfo = RequestMappingInfo
                .paths(path).methods(apiInfo.apiReqMethod())
                .build();
        Method handlerMethod = ReflectionUtils.findMethod(RequestController.class,"invoke",null);
        requestMappingHandlerMapping.registerMapping(requestMappingInfo,applicationContext.getBean(beanName),handlerMethod);
        REQINFOCACHE.put(beanName,requestMappingInfo);
    }

    public void unregisterMapping(ApiInfo apiInfo) throws Exception {
        unregisterMapping(apiInfo.getId());
    }
    public void unregisterMapping(String apiKey) throws Exception {
        String beanName = "Bean_"+ apiKey;
//        final RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)
//                applicationContext.getBean("requestMappingHandlerMapping");
        if (requestMappingHandlerMapping != null) {
            Object controller = applicationContext.getBean(beanName);
            if (controller == null) {
                return;
            }
            requestMappingHandlerMapping.unregisterMapping(REQINFOCACHE.get(beanName));
//            final Class<?> targetClass = controller.getClass();
//            ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
//                public void doWith(Method method) {
//                    Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
//                    try {
//                        Method createMappingMethod = RequestMappingHandlerMapping.class.
//                                getDeclaredMethod("getMappingForMethod", Method.class, Class.class);
//                        createMappingMethod.setAccessible(true);
//                        RequestMappingInfo requestMappingInfo = (RequestMappingInfo)
//                                createMappingMethod.invoke(requestMappingHandlerMapping, specificMethod, targetClass);
//                        if (requestMappingInfo != null) {
//                            requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
//                        }
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//            }, ReflectionUtils.USER_DECLARED_METHODS);

            //卸载bean
            defaultListableBeanFactory.removeBeanDefinition(beanName);
        }

        WORKINGBIMAP.remove(beanName);
    }

    private synchronized void putMappingWorking(String key,String value) {
        if (WORKINGBIMAP.containsKey(key)){
            throw new RuntimeException("已激活");
        }
        if (WORKINGBIMAP.containsValue(value)){
            throw new RuntimeException("已存在");
        }
        WORKINGBIMAP.put(key,value);
    }

    public boolean checkHasWorking(String key){
        return WORKINGBIMAP.containsKey("Bean_"+key);
    }

}
